Android OpenGL的简单使用(12):GLES20纹理的裁剪旋转和缩放

Posted by alonealice on 2021-01-13

着色器程序(Shader)的最终目的就是确定图形的顶点(Vertex)坐标和片元(Fragment)颜色。其实这正是 OpenGL 提供的最基本、最核心的操作原语,我们想要用 OpenGL 实现任何效果,无论是静止的光影、色彩、形状,还是运动的物理效果、粒子效果,归根结底都是要根据时间和位置确定顶点坐标和片元颜色。

常用 2D 纹理变换,其核心思想就是调整纹理坐标和顶点坐标

处理框架:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void setTransformation(final Transformation transformation) {
//裁剪
if (transformation.cropRect != null) {
resolveCrop(transformation.cropRect.left, transformation.cropRect.top,
transformation.cropRect.right - transformation.cropRect.left, transformation.cropRect.bottom - transformation.cropRect.top);
}
//翻转
if (transformation.flip != 0) {
resolveFlip(transformation.flip);
}
//旋转
if (transformation.rotation != 0) {
resolveRotate(transformation.rotation);
}
//缩放
if (transformation.inputSize != null && transformation.outputSize != null) {
resolveScale(transformation.inputSize.right - transformation.inputSize.left, transformation.inputSize.bottom - transformation.inputSize.top,
transformation.outputSize.right - transformation.outputSize.left, transformation.outputSize.bottom - transformation.outputSize.top,
transformation.scaleType);
}
}

裁剪

裁剪实际上是修改TEX_VERTEX的坐标值

1
2
3
4
5
6
private final float[] TEX_VERTEX = {   // in clockwise order:
0, 1, // left top
1, 1, // right top
1, 0, // right bottom
0, 0, // left bottom
};

修改的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void resolveCrop(float x, float y, float width, float height) {
float minX = x;
float minY = y;
float maxX = minX + width;
float maxY = minY + height;

// left bottom
TEX_VERTEX[0] = minX;
TEX_VERTEX[1] = minY;
// right bottom
TEX_VERTEX[2] = maxX;
TEX_VERTEX[3] = minY;
// left top
TEX_VERTEX[4] = minX;
TEX_VERTEX[5] = maxY;
// right top
TEX_VERTEX[6] = maxX;
TEX_VERTEX[7] = maxY;
}

调用方法:

1
2
3
4
5
6
7
8
9
10
11
12
public GlRender() {

//裁剪
Transformation transformation = new Transformation();
RectF rect = new RectF(0.8f, 0, 1f, 1);
transformation.cropRect = rect;

setTransformation(transformation);
mBuffer = Util.getFloatBuffer(VERTEX);
mTexVertexBuffer = Util.getFloatBuffer(TEX_VERTEX);
mVertexIndexBuffer = Util.getShortBuffer(VERTEX_INDEX);
}

翻转

翻转跟裁剪一样,也是修改TEX_VERTEX数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void resolveFlip(int flip) {
switch (flip) {
case Transformation.FLIP_HORIZONTAL:
swap(TEX_VERTEX, 0, 2);
swap(TEX_VERTEX, 4, 6);
break;
case Transformation.FLIP_VERTICAL:
swap(TEX_VERTEX, 1, 5);
swap(TEX_VERTEX, 3, 7);
break;
case Transformation.FLIP_HORIZONTAL_VERTICAL:
swap(TEX_VERTEX, 0, 2);
swap(TEX_VERTEX, 4, 6);
swap(TEX_VERTEX, 1, 5);
swap(TEX_VERTEX, 3, 7);
break;
case Transformation.FLIP_NONE:
default:
break;
}
}
1
2
3
 Transformation transformation = new Transformation();
transformation.flip = Transformation.FLIP_VERTICAL;
setTransformation(transformation);

旋转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private void resolveRotate(int rotation) {
switch (rotation) {
case Transformation.ROTATION_90:
/**
* 0,0,
* 0,1,
* 1,1,
* 1,0
*/
swap(TEX_VERTEX, 1, 5);
swap(TEX_VERTEX, 2, 6);
break;
case Transformation.ROTATION_180:
/**
* 1,0,
* 0,0,
* 0,1,
* 1,1
*/
swap(TEX_VERTEX, 0, 4);
swap(TEX_VERTEX, 1, 5);
swap(TEX_VERTEX, 2, 6);
swap(TEX_VERTEX, 3, 7);
break;
case Transformation.ROTATION_270:
/**
* 1,1,
* 1,0,
* 0,0,
* 0,1
*/
swap(TEX_VERTEX, 0, 4);
swap(TEX_VERTEX, 3, 7);
break;
case Transformation.ROTATION_0:
default:
break;
}
}
1
2
3
Transformation transformation = new Transformation();
transformation.rotation = Transformation.ROTATION_270;
setTransformation(transformation);

缩放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
private void resolveScale(int inputWidth, int inputHeight, int outputWidth,
int outputHeight, int scaleType) {
if (scaleType == Transformation.SCALE_TYPE_FIT_XY) {
// The default is FIT_XY
return;
}

// Note: scale type need to be implemented by adjusting
// the vertices (not textureCoords).
if (inputWidth * outputHeight == inputHeight * outputWidth) {
// Optional optimization: If input w/h aspect is the same as output's,
// there is no need to adjust vertices at all.
return;
}

float inputAspect = inputWidth / (float) inputHeight;
float outputAspect = outputWidth / (float) outputHeight;

if (scaleType == Transformation.SCALE_TYPE_CENTER_CROP) {
if (inputAspect < outputAspect) {
float heightRatio = outputAspect / inputAspect;
VERTEX[1] *= heightRatio;
VERTEX[4] *= heightRatio;
VERTEX[7] *= heightRatio;
VERTEX[10] *= heightRatio;
} else {
float widthRatio = inputAspect / outputAspect;
VERTEX[0] *= widthRatio;
VERTEX[3] *= widthRatio;
VERTEX[6] *= widthRatio;
VERTEX[9] *= widthRatio;
}
} else if (scaleType == Transformation.SCALE_TYPE_CENTER_INSIDE) {
if (inputAspect < outputAspect) {
float widthRatio = inputAspect / outputAspect;
VERTEX[0] *= widthRatio;
VERTEX[3] *= widthRatio;
VERTEX[6] *= widthRatio;
VERTEX[9] *= widthRatio;
} else {
float heightRatio = outputAspect / inputAspect;
VERTEX[1] *= heightRatio;
VERTEX[4] *= heightRatio;
VERTEX[7] *= heightRatio;
VERTEX[10] *= heightRatio;
}
}
}
1
2
3
4
5
6
Rect rect = new Rect(0, 0, 1, 1);
transformation.inputSize = rect;
Rect rect2 = new Rect(0, 0, 1, 2);
transformation.outputSize = rect2;
transformation.scaleType = Transformation.SCALE_TYPE_CENTER_CROP;
setTransformation(transformation);

缩放修改的是VERTEX。